package org.springframework.aop.aspectj;

import org.aspectj.weaver.tools.PointcutExpression;
import org.aspectj.weaver.tools.PointcutParser;
import org.aspectj.weaver.tools.PointcutPrimitive;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;

import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;

/**
 * @author derekyi
 * @date 2020/12/5
 */



/*、
最常用的切点表达式是AspectJ的切点表达式。需要匹配类，定义ClassFilter接口；匹配方法，
定义MethodMatcher接口。PointCut需要同时匹配类和方法，包含ClassFilter和MethodMatcher，
AspectJExpressionPointcut是支持AspectJ切点表达式的PointCut实现，简单实现仅支持execution函数。

*/

//这个类继承了两个不同的接口ClassFilter，MethodMatcher。提供了两个方法名称一样的方法重写，但是参数不同
	//一个用来判断类，一个用来判断method和类
public class AspectJExpressionPointcut implements Pointcut, ClassFilter, MethodMatcher {
	//set集合里存的是切入点表达式的，字符串关键词。
	private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet<PointcutPrimitive>();

	static {
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION);
	}

	//这个就是返回的切入点表达式实例。我们后面匹配的时候需要用它
	private final PointcutExpression pointcutExpression;


	public AspectJExpressionPointcut(String expression) {
		//先得到PointcutParser切入点解析器，传入当前类类加载器，和SUPPORTED_PRIMITIVES（上面的成员变量）。用于规定如何解析
		PointcutParser pointcutParser = PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution
				(SUPPORTED_PRIMITIVES, this.getClass().getClassLoader());

		//把字符串传入PointcutParser切入点解析器，进行解析，匹配字符串
		//之后会返回一个叫做（切点表达式）的实例。是一个成员变量
		pointcutExpression = pointcutParser.parsePointcutExpression(expression);
	}

	//你传入的类或者方法，和之前传入的字符串表达式匹配（判断是不是符合）
	@Override
	public boolean matches(Class<?> clazz) {
		//判断你传入的类是不是，匹配的类（是否属于）
		return pointcutExpression.couldMatchJoinPointsInType(clazz);
		//如果一致，就说明已经铺货了，就会返回true
	}

	@Override
	public boolean matches(Method method, Class<?> targetClass) {
		//判断你传入的类和方法是否符合（切点表达式有可能是加强方法）
		return pointcutExpression.matchesMethodExecution(method).alwaysMatches();
	}



	//这俩方法是Pointcut接口重写的类。
	@Override
	public ClassFilter getClassFilter() {
		return this;
	}

	@Override
	public MethodMatcher getMethodMatcher() {
		return this;
	}
}
